% $File: peripheral.tex
% $Date: Fri Mar 14 21:36:58 2014 +0800
% $Author: jiakai <jia.kai66@gmail.com>

\section{外设}
\subsection{串口与通信}
开发板使用串口和PC机通信。老师提供了一套串口通信的VHDL代码，
但经过测试发现在115200波特率下其连续接收PC端发送的数据时并容易丢包。
后来采取了\url{http://www.fpga4fun.com/SerialInterface.html}上的代码，
要稳定许多。其核心思想在于，接收时使用高频时钟在每个信号周期内多次采样，
并通过滤波得到稳定的数据信号。对串口的解码和编码也被放在了FPGA中进行，
这样CPLD仅负责对TX/RX端口的转发，有两个好处：(1)串口数据不需要占用内存数据线，
也就无需处理冲突，简化了设计；(2)占用更少的FPGA/CPLD互连线，
为后面ps/2键盘的实现提供了方便。

通信方面，我们设计了一套简单的通信协议，可以对flash和RAM进行读写。
其核心流程是，由PC端发起操作，先传给开发板一个操作码，
表示接下来的操作是读还是写，对象是RAM还是flash，或者是擦除flash；
随后PC端向开发板传送操作的起、止地址，接下来就是数据，
通信结束后开发板向PC返回接收到的所有字节的异或值作为校验码。
经测试，实际传输速率约10k/s。

基于这样的通信协议，在PC端用python实现了通信库，
可以对大段数据进行分段传输和校验。在开发板上，
分别用verilog及汇编在硬件、软件层面实现了接收端，方便数据的传输及后期的调试。
其中。verilog接收端主要用于早期开发；在CPU功能相对完善后，
就将汇编的接收端写入了引导ROM，
可以通过拨码开关选择引导ROM的内容是接收端还是ELF加载器，方便对操作系统的调试。


\subsection{VGA\label{sec:vga}}
为了充分利用50MHz的时钟，我们选择了$800\times 600$@72Hz的VGA模式，
具体时序可参考\url{http://tinyvga.com/vga-timing/800x600@72Hz}。
我们使用了xilinx ipcore在FPGA内生成了一块RAM作为VGA的缓存，
每个像素使用一个byte，为256色。考虑到CPU速度有限，VGA的实际分辨率为
$400\times 300$，在显示时由硬件把一个像素扩展为四个像素。为了加速寻址，
VGA缓存的实际大小为$512 \times 300$，
这样程序中就可以通过一次位移和一次加法计算出任意像素的偏移量。
而为了把这段缓存映射到物理内存中，每个字节被补成了4字节的字，
因此VGA缓存占用的物理地址空间是$512\times 300 \times 4 = 614400$。


\subsection{ps/2键盘\label{sec:ps2}}
我们还加入了对ps/2键盘的简单支持。CPLD负责对原始的信号进行解码及校验，
将扫描码分为高4位/低4位两部分依次传送到FPGA中，这样做是为了减少对互连线的占用。
FPGA处理按下、释放事件以及维护shift状态，当键被按下时产生一个中断，
并将传给操作系统的键盘码置为shift状态+ascii码低7位。
当时为了简化实现，采取了这样一种简陋的方式。
当然一个更好的方案是直接把原始扫描码传给操作系统，
并且维护一个未读取的扫描码缓存，以防止操作系统的处理速度跟不上按键速度。

% vim: filetype=tex foldmethod=marker foldmarker=f{{{,f}}}

